#include "GeneralLibrary/Printf.h"
#include "GeneralLibrary/Lib.h"
#include "ExceptionManagement/Gate.h"
#include "ExceptionManagement/Trap.h"
#include "MemoryManagement/Malloc.h"
#include "ProcessManagement/Task.h"
#include "ProcessManagement/SMP.h"
#include "ProcessManagement/Cpu.h"
#include "ProcessManagement/KernelTimer/HEPT.h"
#include "ProcessManagement/SoftIRQ.h"
#include "ProcessManagement/KernelTimer/Timer.h"
#include "InterruptManagement/APIC.h"
//#if  APIC
//#include "InterruptManagement/APIC.h"
//#else
//
//#include "InterruptManagement/8259A.h"
//
//#endif



/**
 * 这四个已经在 Kernel.lds 里面定义了
 */
extern char _text;
extern char _etext;
extern char _edata;
extern char _end;

extern spinlock_T SMPLock;

extern Tss initTss[NR_CPUS];

GlobalMemoryDescriptor memoryManagementStruct = {{0}, 0};

int globalAPUNumber = 0;

// 内核程序的入口点
void startKernel(void) {

    struct INT_CMD_REG icrEntry;
    unsigned int *ptr = NULL;

    // 1. 设置屏幕的分辨率
    displayInfo.resolutionX = 1440;
    displayInfo.resolutionY = 900;

    // 2. 设置光标的初始位置
    displayInfo.cursorPositionX = 0;
    displayInfo.cursorPositionY = 0;

    // 3. 设置字符的尺寸
    displayInfo.charSizeWidth = 8;
    displayInfo.charSizeHeight = 16;

    // 4. 设置帧缓存首地址和帧缓存的长度
    displayInfo.fontBufferAddr = (int *)0xFFFF800003000000;     //这个是帧缓存的线性地址，这里是在内核执行头程序里面定义的
    displayInfo.fontBufferLength =
            (displayInfo.resolutionX * displayInfo.resolutionY * 4 + PAGE_4K_SIZE - 1) & PAGE_4K_MASK_CODE;

    spinInit(&displayInfo.printkLock);

    // 这里不能重复加载，否则就会出错的
    loadTR(10);

    // 加载任务状态段
    setTSS64((unsigned long *)&initTss[0], _stack_start, _stack_start, _stack_start, _stack_start,
             0xffff800000007c00, 0xffff800000007c00, 0xffff800000007c00, 0xffff800000007c00, 0xffff800000007c00);

    // 初始化系统向量
    sysVectorInit();

//    printfColor(GREEN, BLACK, "test!!!: %lx\n", _stack_start);
    printfColor(GREEN, BLACK, "initTaskUnion: %lx\n", &initTaskUnion);
//    int i = 1 / 0;
//    initCpu();

    // 将内核的段信息存放到全局变量里面
    memoryManagementStruct.kernelStartCode = (unsigned long) &_text;
    memoryManagementStruct.kernelEndCode = (unsigned long) &_etext;
    memoryManagementStruct.kernelEndData = (unsigned long) &_edata;
    memoryManagementStruct.kernelEndBrk = (unsigned long) &_end;

//    printfColor(GREEN, BLACK, "test!!!\n");

    // 初始化内存
    initMemory();

    // 初始化内存池
    slabInit();

    frameBufferInit();

//    printfColor(GREEN, BLACK, "test!!!\n");

    ptr = (unsigned char *) kmalloc(STACK_SIZE, 0) + STACK_SIZE;
    ((Task *) (ptr - STACK_SIZE))->cpuID = 0;

    initTss[0].ist1 = (unsigned long) ptr;
    initTss[0].ist2 = (unsigned long) ptr;
    initTss[0].ist3 = (unsigned long) ptr;
    initTss[0].ist4 = (unsigned long) ptr;
    initTss[0].ist5 = (unsigned long) ptr;
    initTss[0].ist6 = (unsigned long) ptr;
    initTss[0].ist7 = (unsigned long) ptr;

    pageTableInit();

    // 初始化中断
//#if  APIC
    APICDeviceInit();
//#else
//    init8259A();
//#endif

    scheduleInit();

    softIRQInit();

    SMPInit();

    // 为可视化做准备
//    icrEntry.vector = 0x00;
//    icrEntry.deliverMode = APIC_ICR_IOAPIC_INIT;
//    icrEntry.destMode = ICR_IOAPIC_DELV_PHYSICAL;
//    icrEntry.deliverStatus = APIC_ICR_IOAPIC_Idle;
//    icrEntry.res_1 = 0;
//    icrEntry.level = ICR_LEVEL_DE_ASSERT;
//    icrEntry.trigger = APIC_ICR_IOAPIC_Edge;
//    icrEntry.res_2 = 0;
//    icrEntry.destShorthand = ICR_ALL_EXCLUDE_Self;
//    icrEntry.res_3 = 0;
//    icrEntry.destination.x2apicDestination = 0x00;
//
//    // 通知其他处理器开始运行了
//    wrmsr(0x830, *(unsigned long *) &icrEntry);    // INIT IPI
//
//    for (globalAPUNumber = 1; globalAPUNumber < 4; globalAPUNumber++) {
//
//        printfColor(GREEN, BLACK, "11!!!\n");
//        spinLock(&SMPLock);
//
//        ptr = (unsigned char *) kmalloc(STACK_SIZE, 0);
//
//        _stack_start = (unsigned long) ptr + STACK_SIZE;
//
//        ((Task *) ptr)->cpuID = globalAPUNumber;
//
//        memset(&initTss[globalAPUNumber], 0, sizeof(Tss));
//
//        initTss[globalAPUNumber].rsp0 = _stack_start;
//        initTss[globalAPUNumber].rsp1 = _stack_start;
//        initTss[globalAPUNumber].rsp2 = _stack_start;
//
//        ptr = (unsigned char *) kmalloc(STACK_SIZE, 0) + STACK_SIZE;
//        ((Task *) (ptr - STACK_SIZE))->cpuID = globalAPUNumber;
//
//        initTss[globalAPUNumber].ist1 = (unsigned long) ptr;
//        initTss[globalAPUNumber].ist2 = (unsigned long) ptr;
//        initTss[globalAPUNumber].ist3 = (unsigned long) ptr;
//        initTss[globalAPUNumber].ist4 = (unsigned long) ptr;
//        initTss[globalAPUNumber].ist5 = (unsigned long) ptr;
//        initTss[globalAPUNumber].ist6 = (unsigned long) ptr;
//        initTss[globalAPUNumber].ist7 = (unsigned long) ptr;
//
//        setTSSDescriptor(10 + globalAPUNumber * 2, &initTss[globalAPUNumber]);
//
//        icrEntry.vector = 0x20;
//        icrEntry.deliverMode = ICR_Start_Up;
//        icrEntry.destShorthand = ICR_No_Shorthand;
//        icrEntry.destination.x2apicDestination = globalAPUNumber;
//
//        wrmsr(0x830, *(unsigned long *) &icrEntry);    // Start-up IPI
//        wrmsr(0x830, *(unsigned long *) &icrEntry);    // Start-up IPI
//
//    }
//
//    icrEntry.vector = 0xc8;
//    icrEntry.destination.x2apicDestination = 1;
//    icrEntry.deliverMode = APIC_ICR_IOAPIC_Fixed;
//
//    wrmsr(0x830, *(unsigned long *) &icrEntry);
//
//    icrEntry.vector = 0xc9;
//    wrmsr(0x830, *(unsigned long *) &icrEntry);

    timerInit();

    // 初始化HPET定时器
    HPETInit();

//    printfColor(GREEN, BLACK, "IDT_TABLE: %lx\n", IDT_TABLE);

    taskInit();
    sti();

    while (1)
        hlt();

}